/**
 * 
 */
package tests;

import static org.junit.Assert.*;

import javax.persistence.*;
import jpaUtils.*;

import java.util.*;

import org.hibernate.LazyInitializationException;
import org.junit.*;


import booksManagement.*;
import subscribersManagement.*;
import loansManagement.*;
import main.Library;

import exceptions.*;

/**
 * @author        user
 */
public class PersistentLibraryTest {
	
	private Scanner scanStr = new Scanner(System.in);
	private Scanner scanInt = new Scanner(System.in);
	/**
   * @uml.property  name="subscriberDAO"
   * @uml.associationEnd  
   */
	private SubscriberDAO subscriberDAO;
	/**
   * @uml.property  name="bookDAO"
   * @uml.associationEnd  
   */
	private static Library lib = new Library();
	/**
   * @return
   * @uml.property  name="bookDAO"
   */
	public static Library getLib(){
		return lib;
	}
	/**
   * @uml.property  name="bookDAO"
   * @uml.associationEnd  
   */
	private BookDAO bookDAO;
	/**
   * @uml.property  name="copyDAO"
   * @uml.associationEnd  
   */
	private CopyDAO copyDAO;
	/**
   * @uml.property  name="loanDAO"
   * @uml.associationEnd  
   */
	private LoanDAO loanDAO;
	/**
   * @uml.property  name="dvdDAO"
   * @uml.associationEnd  
   */
	private DvdDAO dvdDAO;
	/**
   * @uml.property  name="mediaDAO"
   * @uml.associationEnd  
   */
	private MediaDAO mediaDAO;
	private List<String> authors1= new ArrayList<String>();;
	private List<String> authors2= new ArrayList<String>();;

	private void createMedias() throws BadParametersException {
		EntityManager em;
		EntityTransaction tx;		
		bookDAO = new BookDAO();
		mediaDAO = new MediaDAO();
		dvdDAO = new DvdDAO();
		copyDAO= new CopyDAO();
		
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		
		if (bookDAO.isEmpty() && mediaDAO.isEmpty() && dvdDAO.isEmpty() ) {
			System.out.println("===== Create Media data in memory ====");
			authors1.add("Elmasri");
			authors1.add("Navathe");
			authors2.add("Peter Gulutzan");
			authors2.add("Trudy Pelzer");
			Book b1 = new Book("Fundamentals of Database Systems", authors1, new GregorianCalendar(), "0-321-20228-4");
			Book b2 = new Book("SQL-99 Complete, Really", authors2, new GregorianCalendar(), "0-87930-568-1", 2);
			Book b3 = new Book("Pandore menacée", authors1, UtilsDate.asCalendar(UtilsDate.stringToDate("12/11/2004")), "978-2-8112-0036-7", 5);
			DVD d1 = new DVD("La guerre des boutons", new GregorianCalendar(),"0654744657",2);
			DVD d2 = new DVD("Microcosmos", new GregorianCalendar(),"136658783");
			b1.addCopy();
			d1.addCopy();
			Copy cb1 = b1.getCopies().get(0);
			Copy cd1 = d1.getCopies().get(2);
			System.out.println("===== Persist media data ====");
			try {
				mediaDAO.add(b1);
				lib.addMedia(b2);
				mediaDAO.add(d1);
				mediaDAO.add(d2);
				lib.addMedia(b3);
				copyDAO.add(cd1);
				copyDAO.add(cb1);
				
			} catch (Exception pe) {
				System.err.println("Exception when persisting data");
				JPAUtil.closeEntityManager();
				pe.printStackTrace();
			}
		}
		System.out.println("===== Display media data =====");
		System.out.println("Nombre de medias : " + mediaDAO.getContent().size());
		System.out.println(bookDAO.toString());
		System.out.println(dvdDAO.toString());
		System.out.println(mediaDAO.toString());
		System.out.println("===== Display copy data =====");
		System.out.println(copyDAO.toString());
		tx.commit();
		JPAUtil.closeEntityManager();

	}


	private void createSubscribers() throws BadParametersException {
		EntityManager em;
		EntityTransaction tx;		

		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();

		subscriberDAO = new SubscriberDAO();
		if (subscriberDAO.isEmpty()) {
			System.out.println("===== Create Subscriber data in memory ====");
			Subscriber 	s1 = new Subscriber("Vincent", "Airo", new GregorianCalendar(1960, 12, 13));
			Subscriber 	s2 = new Subscriber("Betina", "Chtilfiz", new GregorianCalendar(1965, 02, 25));
			Entitled 	s3 = new Entitled("Victor", "Chtilfiz", new GregorianCalendar(1997, 02, 20), s2);
			Entitled 	s4 = new Entitled("Luisa", "Chtilfiz", new GregorianCalendar(1993, 07, 30), s2);
			System.out.println("===== Persist Subscriber data ====");
			try {
				subscriberDAO.add(s1);
				subscriberDAO.add(s2);
				subscriberDAO.add(s3);
				subscriberDAO.add(s4);
			} catch (Exception pe) {
				System.err.println("Exception when persisting data");
				JPAUtil.closeEntityManager();
				pe.printStackTrace();
			}
		}
		System.out.println("===== Display Subscriber data =====");
		System.out.println(subscriberDAO.toString());

		tx.commit();
		JPAUtil.closeEntityManager();
	}
	

	private void createLoans() throws BadParametersException,LentBookException, TooManyLoansException, BookExistsException, SubscriberExistsException, ReservedCopyException {
		EntityManager em;
		EntityTransaction tx;		

		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();

		loanDAO = new LoanDAO();
		if (loanDAO.isEmpty()) {
			System.out.println("===== Create Loan data in memory ====");
			authors1.add("Elmasri");
			authors1.add("Navathe");
			Book b1 = (Book)mediaDAO.get("0-321-20228-4");
			DVD d1 = (DVD)mediaDAO.get("0654744657");
			Subscriber 	s1 = subscriberDAO.get(1);
			Subscriber 	s2 = subscriberDAO.get(2);
			b1.addCopy();
			d1.addCopy();
			Copy cb1 = b1.getCopies().get(0);
			Copy cd1 = d1.getCopies().get(1);
			Loan l1 = new Loan(cb1, s1);
			Loan l2 = new Loan(cd1, s2);
			System.out.println("===== Persist Loan data ====");
			try {
				loanDAO.add(l1);
				loanDAO.add(l2);
			} catch (Exception pe){
				System.err.println("Exception when persisting data");
				JPAUtil.closeEntityManager();
				pe.printStackTrace();
			}
		}
		System.out.println("===== Display Loan data =====");
		System.out.println(loanDAO.toString());

		tx.commit();
		JPAUtil.closeEntityManager();
			
		}

	
	@Before
	public void beforeTests() throws BadParametersException, TooManyLoansException, LentBookException, SubscriberExistsException, BookExistsException, ReservedCopyException  {
		createSubscribers();
		createMedias();
		createLoans();
		lib.setMedias(mediaDAO);
		lib.setCopies(copyDAO);
		lib.setSubscribers(subscriberDAO);
		lib.setLoans(loanDAO);
	}
	
	@Test
	public void addMediaWithoutCopy() throws BadParametersException{
		EntityManager em;
		EntityTransaction tx;
		
		
		System.out.println("Number of medias before add : " +mediaDAO.getContent().size());
		System.out.println("Media title ?");
		String title = scanStr.nextLine();
		System.out.println("author ?");
		ArrayList<String> authors = new ArrayList<String>();
		authors.add(scanStr.nextLine());
		System.out.println("editionDate (dd/mm/yyyy) ?");
		Date editionDate = UtilsDate.stringToDate(scanStr.nextLine());
		GregorianCalendar editionDAte = UtilsDate.asCalendar(editionDate);
		System.out.println("Isbn ?");
		String isbn = scanStr.nextLine();
		Book b = new Book(title, authors, editionDAte, isbn);
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		
		mediaDAO.add(b);
		
		tx.commit();
		JPAUtil.closeEntityManager();
		System.out.println("Number of medias after add : " +mediaDAO.getContent().size());
		
	}
	
	@Test
	public void testAddmediaWithCopies() throws BadParametersException, BookExistsException{
		EntityManager em;
		EntityTransaction tx;
		
		
		Book b = new Book("Testbook2", authors1, new GregorianCalendar(), "021446558", 2);
		//Book b2 = new Book("Testbook3", authors1, new GregorianCalendar(), "021446558", 2);
		
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		lib.addMedia(b);
		//lib.addMedia(b2);
		
		tx.commit();
		JPAUtil.closeEntityManager();	
	}
	
	@Test
	public void testAddCopyToPreexistingMedia() throws BadParametersException, BookExistsException{
		EntityManager em;
		EntityTransaction tx;
		Media m = lib.listMedias().get(3);
		System.out.println(m.getCopies().size());
		
		
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		lib.addMediaCopy(m,1);
		
		
		tx.commit();
		JPAUtil.closeEntityManager();
		System.out.println(m.getCopies().size());
	}
	
	/*@Test
	public void testAddCopyToNonExistingMedia(){
		EntityManager em;
		EntityTransaction tx;
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		try{
		Book b =	new Book()
		tx.begin();
		lib.addMediaCopy(b,1);
		}catch(Exception pe){
			
		}
		
		
		tx.commit();
		JPAUtil.closeEntityManager();	
	}*/
	
	@Test(expected = LentBookException.class)
	public void testDeleteMediaWithLentCopies() throws BadParametersException, BookExistsException, LentBookException{
		EntityManager em;
		EntityTransaction tx;
		
		Media m = lib.getMedias().get("0-321-20228-4");
		
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		lib.deleteMedia(m);
		
		
		tx.commit();
		JPAUtil.closeEntityManager();	
	}
	
	@Test
	public void testDeleteMediaNoCopyLent() throws BadParametersException, BookExistsException, LentBookException{
		EntityManager em;
		EntityTransaction tx;
		System.out.println(lib.getMedias().get("0-87930-568-1"));
		Media m = lib.getMedias().get("0-87930-568-1");
		System.out.println("Nombre de médias : "+ lib.getMedias().size());
		
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		lib.deleteMedia(m);
		
		
		tx.commit();
		JPAUtil.closeEntityManager();	
		System.out.println("Nombre de médias : "+ lib.getMedias().size());
	}

	@Test
	public void testDeleteNoLentCopy() throws BadParametersException, BookExistsException, LentBookException{
		EntityManager em;
		EntityTransaction tx;
		
		Media m = lib.getMedias().get("978-2-8112-0036-7");

		Scanner scan = new Scanner(System.in);
		System.out.println("Tapez entrée");
		scan.nextLine();
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		lib.deleteCopy(m.getCopies().get(1));
		
		
		tx.commit();
		JPAUtil.closeEntityManager();	
	}
	
	@Test
	public void testLendCopy() throws SubscriberExistsException, BookExistsException{
		EntityManager em;
		EntityTransaction tx;
		
		System.out.println("Subscriber id ?");
		Subscriber s = lib.getSubscribers().get(scanInt.nextInt());
		System.out.println("Copy id ?");
		Copy c = lib.getCopies().get(scanInt.nextInt());
		
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		try{
		tx.begin();
		lib.lend(c,s);
		System.out.println("Loan Ok");
		System.out.println(s.getCurrentLoans());
		
		
		tx.commit();
		}catch(Exception e){
			e.printStackTrace();
		}
		JPAUtil.closeEntityManager();	
		
	}
	
	@Test
	public void testReturnCopy() throws BadParametersException, BookExistsException, LentBookException, LoanExistsException{
		EntityManager em;
		EntityTransaction tx;
		System.out.println(lib.listMedias().get(1));
		Loan l = lib.listLoans().get(1);
		
		em= JPAUtil.getEntityManager();
		tx=em.getTransaction();
		tx.begin();
		lib.returnCopy(l.getCopy());
		
		
		tx.commit();
		JPAUtil.closeEntityManager();	
	}
	@Test
	public void testNoTATestButStoresData() {
		System.out.println("***************Store data***************");
	}

	@Test
	public void testDetachedData1() throws SubscriberExistsException {
		long sNumber=3;

		EntityManager em= JPAUtil.getEntityManager();
		EntityTransaction tx=em.getTransaction();
		tx.begin();
		Subscriber s= subscriberDAO.get(sNumber);
		Entitled e=(Entitled)s;

		tx.commit();
		JPAUtil.closeEntityManager();

		System.out.println("\n Subscriber number "+ sNumber +" is "+s);

	}

	@Test(expected=LazyInitializationException.class)
	public void testDetachedData2() throws SubscriberExistsException {

		long sNumber=3;

		EntityManager em= JPAUtil.getEntityManager();
		EntityTransaction tx=em.getTransaction();
		tx.begin();

		Subscriber s= subscriberDAO.get(sNumber);
		Entitled e=(Entitled)s;

		tx.commit();
		JPAUtil.closeEntityManager();
		

		System.out.println("\n Subscriber number "+ sNumber +" is "+e);

		List<Entitled> entitles = e.getMainSubscriber().getEntitles();

		if (entitles == null) 
			System.out.println("\n No entitles for " + e.getMainSubscriber());
		else
			System.out.println("\n Entitles of "+ e.getMainSubscriber() +" are "+ entitles);
	}

	
	@Test
	public void testUpdateSimpleTypedValue1() throws SubscriberExistsException {

		EntityManager em = JPAUtil.getEntityManager();
		EntityTransaction tx= em.getTransaction();
		tx.begin();

		Subscriber subscriber = subscriberDAO.GetSingleSubscriberByLastName("Airo");
		System.out.println("Subscriber.firstName=" + subscriber.getFirstName());
		tx.commit();
		JPAUtil.closeEntityManager();

		subscriber.setFirstName("my new firstname");
		
		em = JPAUtil.getEntityManager();
		tx = em.getTransaction();
		tx.begin();

		em.merge(subscriber);
		       
		subscriber = subscriberDAO.GetSingleSubscriberByLastName("Airo");
		System.out.println("Subscriber.firstname=" + subscriber.getFirstName());

		tx.commit();
		JPAUtil.closeEntityManager();
	}
	
	
	@Test
	public void testUpdateSimpleTypedValue2() throws SubscriberExistsException {

		EntityManager em = JPAUtil.getEntityManager();
		EntityTransaction tx= em.getTransaction();
		tx.begin();

		Subscriber subscriber = subscriberDAO.GetSingleSubscriberByLastName("Airo");
		System.out.println("Before update \n Subscriber variable firstName=" + subscriber.getFirstName());
		tx.commit();
		JPAUtil.closeEntityManager();

		Subscriber pers = new Subscriber();
		pers.setNumber(subscriber.getNumber());
		pers.setLastName(subscriber.getLastName());
		pers.setFirstName("my new firstname");
		
		em = JPAUtil.getEntityManager();
		tx = em.getTransaction();
		tx.begin();

		em.merge(pers);
		       
		
		System.out.println("After update \n firstname in database =" + subscriberDAO.GetSingleSubscriberByLastName("Airo").getFirstName());
		System.out.println(" subscriber variable firstname =" + subscriber.getFirstName());
		System.out.println(" pers variable firstname =" + pers.getFirstName());

		em.merge(subscriber);
		       
		
		System.out.println("After 2nd update \n firstname in database =" + subscriberDAO.GetSingleSubscriberByLastName("Airo").getFirstName());
		System.out.println(" subscriber variable firstname =" + subscriber.getFirstName());
		System.out.println(" pers variable firstname =" + pers.getFirstName());

		tx.commit();
		JPAUtil.closeEntityManager();
		System.out.println(" subscriber variable firstname =" + subscriber.getFirstName());
		System.out.println(" pers variable firstname =" + pers.getFirstName());
	}
	
	
	
	@Test
	public void testManyToOnePartOfBidirectionalAssociationUpdate1() throws SubscriberExistsException {

		
		EntityManager em;
		EntityTransaction tx;
		
		Entitled e;
		Subscriber s1, s2;
		
		em = JPAUtil.getEntityManager();
		tx =em.getTransaction();
		tx.begin();

		e=(Entitled)subscriberDAO.get(3);
		s1= subscriberDAO.get(1);
		s2= subscriberDAO.get(2);


		System.out.println("Before update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());
		e.setMainSubscriber(s1);
		System.out.println("After update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());


		tx.commit();
		JPAUtil.closeEntityManager();

		

		System.out.println("After commit\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());


	}

	@Test
	public void testManyToOnePartOfBidirectionalAssociationUpdate2() throws SubscriberExistsException {

		
		EntityManager em;
		EntityTransaction tx;
		
		Entitled e;
		Subscriber s1, s2;
		
		em = JPAUtil.getEntityManager();
		tx =em.getTransaction();
		tx.begin();

		e=(Entitled)subscriberDAO.get(3);
		s1= subscriberDAO.get(1);
		s2= subscriberDAO.get(2);

		System.out.println("Before update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		e.setMainSubscriber(s1);

		tx.commit();
		JPAUtil.closeEntityManager();

		System.out.println("After update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		em = JPAUtil.getEntityManager();
		tx =em.getTransaction();
		tx.begin();		

		s1= subscriberDAO.get(1);
		s2= subscriberDAO.get(2);

		System.out.println("After commit and reload\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		tx.commit();
		JPAUtil.closeEntityManager();


	}

	
	@Test
	public void testOneTOManyPartOfBidirectionalAssociationUpdate() throws SubscriberExistsException {

		EntityManager em;
		EntityTransaction tx;
		
		Entitled e;
		Subscriber s1, s2;
		
		em = JPAUtil.getEntityManager();
		tx =em.getTransaction();
		tx.begin();

		e=(Entitled)subscriberDAO.get(3);
		s1= subscriberDAO.get(1);
		s2= subscriberDAO.get(2);

		System.out.println("Before update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		s1.addEntitled(e);

		tx.commit();
		JPAUtil.closeEntityManager();

		System.out.println("After update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		em = JPAUtil.getEntityManager();
		tx =em.getTransaction();
		tx.begin();		

		s1= subscriberDAO.get(1);
		s2= subscriberDAO.get(2);

		System.out.println("After commit and reload\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		tx.commit();
		JPAUtil.closeEntityManager();



	}

	
	
	@Test (expected=LazyInitializationException.class)
	public void testAssociationUpdateOutOfTransaction() throws SubscriberExistsException {

		EntityManager em;
		EntityTransaction tx;
		
		Entitled e;
		Subscriber s1, s2;
		
		em = JPAUtil.getEntityManager();
		tx =em.getTransaction();
		tx.begin();

		e=(Entitled)subscriberDAO.get(3);
		s1= subscriberDAO.get(1);
		s2= subscriberDAO.get(2);

		tx.commit();
		JPAUtil.closeEntityManager();

		System.out.println("After commit and Before update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		e.setMainSubscriber(s1);

		System.out.println("After commit and After update\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());


		em = JPAUtil.getEntityManager();
		tx =em.getTransaction();
		tx.begin();

		em.merge(e);
		em.merge(s1);
		em.merge(s2);

		System.out.println("After commit and reload\n Subscriber "+ s1 +" has entitles "+ s1.getEntitles());
		System.out.println(" Subscriber "+ s2 +" has entitles "+ s2.getEntitles());

		tx.commit();
		JPAUtil.closeEntityManager();

	}

	

}
